#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__

#include <iostream>
#include <pthread.h>
#include <string>
#include <queue>

using namespace std;

template <class T>
class BlockQueue
{
public:
    bool IsFull()
    {
        return _cap == _block_queue.size();
    }
    bool IsEmpty()
    {
        return _block_queue.empty();
    }
    BlockQueue(int cap):_cap(cap)
    {
        _productor_wait_num = 0;
        _consumer_wait_num = 0;
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_product_cond, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
    }
    void Push(T& in)//生产者用的接口
    {
        pthread_mutex_lock(&_mutex);//加锁
        while(IsFull())
        {
            //生产线程要等待，在临界区休眠
            //作用：1、让调用进程等待；2、释放之前持有的锁
            _productor_wait_num++;
            pthread_cond_wait(&_product_cond, &_mutex);
            _productor_wait_num--;
        }
        //进行生产
        _block_queue.push(in);
        //通知消费者消费
        if(_consumer_wait_num > 0)
            pthread_cond_signal(&_consumer_cond);

        pthread_mutex_unlock(&_mutex);//解锁
    }
    void Pop(T* out)//消费者用的接口
    {
        pthread_mutex_lock(&_mutex);//加锁
        while(IsEmpty())//用while，保证代码健壮性
        {
            //消费线程要等待，在临界区休眠
            //作用：1、让调用进程等待；2、释放之前持有的锁
            _consumer_wait_num++;
            pthread_cond_wait(&_consumer_cond, &_mutex);
            _consumer_wait_num--;
        }
        //进行消费
        *out = _block_queue.front();
        _block_queue.pop();
        //通知生产者生产
        if(_productor_wait_num > 0)
            pthread_cond_signal(&_product_cond);

        pthread_mutex_unlock(&_mutex);//解锁
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_product_cond);
        pthread_cond_destroy(&_consumer_cond);
    }
private:
    int _cap;// 总上限
    queue<T> _block_queue;// 阻塞队列
    pthread_mutex_t _mutex;//保护_block_queue的锁
    pthread_cond_t _product_cond;//给生产者提供的条件变量
    pthread_cond_t _consumer_cond;//给消费者提供的条件变量
    int _productor_wait_num;//有多少个生产者在等待
    int _consumer_wait_num;// 有多少个消费者在等待
};


#endif